﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Xml;
using ApiBetaSeries.Utils;
using ApiBetaSeries.Factories;

namespace ApiBetaSeries.Model
{
    /// <summary>
    /// Represent a show on api
    /// </summary>
    internal class Show : ApiBetaSeries.IShow
    {
        /// <summary>
        /// Empty constructor
        /// </summary>
        public Show() { }

        #region Attributes
        /// <summary>
        /// Show's Title
        /// </summary>
        public string Title { get; set; }
        /// <summary>
        /// Id on website thetvdb.com
        /// </summary>
        public int Id_thetvdb { get; set; }
        /// <summary>
        /// url on betaseries api
        /// </summary>
        public string Url { get; set; }
        /// <summary>
        /// show's description
        /// </summary>
        public string Description { get; set; }
        /// <summary>
        /// Show's status (canceled, project...)
        /// </summary>
        public ShowStatus Status { get; set; }
        /// <summary>
        /// Link to the show's banner (not download)
        /// </summary>
        public string Banner { get; set; }
        /// <summary>
        /// Kind of show
        /// </summary>
        public List<string> Genres { get; set; }
        /// <summary>
        /// List of episode number by season
        /// </summary>
        public List<int> Seasons { get; set; }

        private Bitmap m_bannerBitmap = null;
        public Bitmap BannerBitmap
        {
            get {
                if (m_bannerBitmap == null && !string.IsNullOrEmpty(Banner))
                {
                    m_bannerBitmap = new Bitmap(Banner);
                }
                return m_bannerBitmap;
            }
        }
        #endregion Attributes

        #region Inherits
        public override bool Equals(object obj)
        {
            if (obj == null) return false;

            if (this.GetType() != obj.GetType()) return false;

            Show s = (Show)obj;
            if (!Object.Equals(this.Title, s.Title)) return false;
            if (!Object.Equals(this.Id_thetvdb, s.Id_thetvdb)) return false;
            if (!Object.Equals(this.Description, s.Description)) return false;
            if (!Object.Equals(this.Url, s.Url)) return false;
            if (!Object.Equals(this.Status, s.Status)) return false;
            if (!Object.Equals(this.Banner, s.Banner)) return false;

            if (this.Seasons == null)
            {
                if (s.Seasons != null) return false;
            } else if (this.Seasons.Count != s.Seasons.Count) return false;


            for (int i = 0; i < this.Seasons.Count; ++i)
            {
                if (!Object.Equals(this.Seasons[i], s.Seasons[i])) return false;
            }

            if (this.Genres == null)
            {
                if (s.Genres != null) return false;
            }
            else if (this.Genres.Count != s.Genres.Count) return false;


            for (int i = 0; i < this.Genres.Count; ++i)
            {
                if (!Object.Equals(this.Genres[i], s.Genres[i])) return false;
            }

            return true;
        }

        public override int GetHashCode()
        {
            return Title.GetHashCode() ^ Url.GetHashCode();
        }

        public override string ToString()
        {
            return Title;
        }
        #endregion Inherits

        #region Methods
        /// <summary>
        /// Get all the season of a show
        /// </summary>
        /// <param name="token">Token of the user</param>
        /// <returns>List of seasons</returns>
        [ApiBetaSeries.Version.ApiMethod(true, "shows/episodes")]
        public List<ISeason> GetSeasons(string token = null)
        {
            List<ISeason> seasons = new List<ISeason>();
            XmlDocument doc = Utils.UtilsXML.GetUrl("/shows/episodes/" + this.Url + ".xml", (!string.IsNullOrEmpty(token) ? "&token=" + token : ""));
            XmlElement xmlseasons = doc["root"]["seasons"];


            foreach (XmlElement s in xmlseasons.GetElementsByTagName("season"))
            {
                ISeason season = SeasonFactory.CreateSeason(this.Url, s);
                seasons.Add(season);
            }
            return seasons;
        }

        /// <summary>
        /// Get all the season of a show
        /// </summary>
        /// <param name="user">the user</param>
        /// <returns>List of seasons</returns>
        [ApiBetaSeries.Version.ApiMethod(false, "shows/episodes")]
        public List<ISeason> GetSeasons(IUser user)
        {
            return GetSeasons(user.Token);
        }

        /// <summary>
        /// Get a specific season of a show
        /// </summary>
        /// <param name="number">Season number</param>
        /// <param name="token">Token of the user</param>
        /// <returns>the season</returns>
        [ApiBetaSeries.Version.ApiMethod(true, "shows/episodes")]
        public ISeason GetSeason(int number, string token)
        {
            ISeason season;
            XmlDocument doc = Utils.UtilsXML.GetUrl("/shows/episodes/" + Url + ".xml", "&season=" + number + (!string.IsNullOrEmpty(token) ? "&token=" + token : ""));
            XmlElement s = doc["root"]["seasons"]["season"];

            if (s == null)
            {
                throw new BetaSeriesException(4005, "Cette saison n'existe pas.");
            }

            season = SeasonFactory.CreateSeason(Url, s);
            return season;
        }

        /// <summary>
        /// Get a specific season of a show
        /// </summary>
        /// <param name="number">Season number</param>
        /// <param name="user">the user</param>
        /// <returns>the season</returns>
        [ApiBetaSeries.Version.ApiMethod(false, "shows/episodes")]
        public ISeason GetSeason(int number, IUser user)
        {
            return GetSeason(number, user.Token);
        }

        /// <summary>
        /// Get a specific episode of a show
        /// </summary>
        /// <param name="seasonNumber">season of the episode</param>
        /// <param name="episodeNumber">episode number</param>
        /// <param name="token">Token of the user</param>
        /// <returns>the episode</returns>
        [ApiBetaSeries.Version.ApiMethod(true, "shows/episodes")]
        public IEpisode GetEpisode(int seasonNumber, int episodeNumber, string token = null)
        {
            IEpisode episode;
            string urlApi = string.Format("/shows/episodes/{0}.xml", Url);
            string param = string.Format("&season={0}&episode={1}", seasonNumber, episodeNumber);
            if (!string.IsNullOrEmpty(token))
                param += "&token=" + token;

            XmlDocument doc = Utils.UtilsXML.GetUrl(urlApi, param);
            XmlElement s = doc["root"]["seasons"]["season"];

            if (s == null)
            {
                throw new BetaSeriesException(4005, "Cette saison n'existe pas.");
            }

            XmlNode e = s.GetElementsByTagName("episode")[0];

            episode = EpisodeFactory.CreateEpisode(e);
            episode.UrlShow =Url;
            episode.Season = seasonNumber;

            return episode;
        }

        /// <summary>
        /// Get the last subtitle of a show
        /// </summary>
        /// <param name="number">number of subtitles you want (between 0 and 100) </param>
        /// <param name="type">VO/VF/VOVF</param>
        /// <returns>list of subtitles</returns>
        [ApiBetaSeries.Version.ApiMethod(true, "subtitles/last")]
        public List<ISubtitle> GetLastSubtitles(int number = 100, SubtitleLanguage type = SubtitleLanguage.VOVF)
        {
            List<ISubtitle> list = new List<ISubtitle>();
            if (type == SubtitleLanguage.Other)
            {
                throw new ArgumentException("Cannot use SubtitleLanguage 'Other' for this request");
            }
            string stype = type.ToString();
            if (number <= 0)
            {
                number = 100;
            }

            XmlDocument doc = Utils.UtilsXML.GetUrl("/subtitles/last/" + Url + ".xml", "&number=" + number + "&language=" + stype);
            XmlElement xe = doc["root"]["subtitles"];

            if (xe == null)
            {
                throw new BetaSeriesException(1003, "Invalid action.");
            }
            foreach (XmlElement sub in xe.GetElementsByTagName("subtitle"))
            {
                ISubtitle s = SubtitleFactory.CreateSubtitle(sub);
                list.Add(s);
            }

            return list;
        }


        /// <summary>
        /// Get all the subtitles for a show
        /// </summary>
        /// <param name="type">VO/VF/VOVF</param>
        /// <returns>List of subtitles</returns>
        [ApiBetaSeries.Version.ApiMethod(true, "subtitles/show")]
        public List<ISubtitle> GetSubtitles(SubtitleLanguage type = SubtitleLanguage.VOVF)
        {
            List<ISubtitle> list = new List<ISubtitle>();
            if (type == SubtitleLanguage.Other)
            {
                throw new ArgumentException("Cannot use SubtitleLanguage : Other for this request");
            }
            string stype = type.ToString();

            XmlDocument doc = Utils.UtilsXML.GetUrl("/subtitles/show/" + Url + ".xml", "&language=" + stype);
            XmlElement xe = doc["root"]["subtitles"];

            if (xe == null)
            {
                throw new BetaSeriesException(1003, "Invalid action.");
            }
            foreach (XmlElement sub in xe.GetElementsByTagName("subtitle"))
            {
                ISubtitle s = SubtitleFactory.CreateSubtitle(sub);
                list.Add(s);
            }

            return list;
        }

        /// <summary>
        /// Recommend this show to a friend
        /// </summary>
        /// <param name="user">identified member</param>
        /// <param name="friend">friend's username</param>
        [ApiBetaSeries.Version.ApiMethod(false, "shows/recommend")]
        public void Recommend(IUser user, string friend)
        {
            Recommend(user.Token, friend);
        }
        /// <summary>
        /// Recommend this show to a friend
        /// </summary>
        /// <param name="token">token of an identified member</param>
        /// <param name="friend">friend's username</param>
        [ApiBetaSeries.Version.ApiMethod(true, "shows/recommend")]
        public void Recommend(string token, string friend)
        {
            string url = string.Format("/shows/recommend/{0}.xml", this.Url);
            string param = string.Format("&token={0}&friend={1}", token, friend);

            XmlDocument doc = Utils.UtilsXML.GetUrl(url, param);
        }
        #endregion Methods
    }
}
